﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once
#include "GmStructure.h"
#include "NdbObjectSchematic.h"
#include "IStructureInstanceJoinBehavior.h"
#include "JoinPositions.h"
#include "DbDataSchema.h"
#include "RegenDataSchema.h"
#include "RegenDataId.h"

namespace gcmp
{
    class IElement;
    class IInstance;
    class IElementJoinBehavior;
    class IGraphicsElementShape;

    class GM_STRUCTURE_EXPORT StructureInstanceJoinBehavior : public NdbObjectSchematic, public IStructureInstanceJoinBehavior
    {
        DBOBJECT_DATA_BEGIN_AND_QUICK_CAST_FROM(gcmp, StructureInstanceJoinBehavior, gcmp::NdbObjectSchematic, 34494040 - 2070 - 4C6F - A413 - 359146FAA515, gmstructure, gcmp::IStructureInstanceJoinBehavior)
            DATA(IDocument*, pDoc)
            DATA(ElementId, OwnerElementId) //ElementJoinElementId
            DATA(JoinType, JoinType)
            DATA(Bool, IsChangeJoinTypeAllowed) //是否允许切换平接和方接
            DATA(Bool, IsChangePriAndSecAllowed) //是否允许切换主次关系
            DBOBJECT_DATA_END
            DECLARE_REGEN_FUNCTIONS(JoinType)
    public:

        //根据指定的连接方式构造StructureInstanceJoinBehavior
        //如果不希望切换连接方式的话，请将isChangeJoinTypeAllowed设为false
        //isChangeJoinTypeAllowed为true的话，会根据计算结果自动切换连接方式
        StructureInstanceJoinBehavior(IDocument* pDoc, JoinType joinType, bool isChangeJoinTypeAllowed);
        virtual ~StructureInstanceJoinBehavior();

        OwnerPtr<IElementJoinBehavior> Clone() const override { return NEW_AS_OWNER_PTR(StructureInstanceJoinBehavior, *this); }

        ElementId GetOwnerElementId() const override { return GetOwnerElementId__(); }
        void SetOwnerElementId(const ElementId& id) override { SetOwnerElementId__(id); }

        IDocument* GetDocument() const override { return m_pDoc; }
        void SetDocument(IDocument* pDoc) override { m_pDoc = pDoc; }
        virtual void ReportInputDataIds(std::vector<RegenDataId> & regenDataIds) const override;
        virtual bool CalculateJoinedGraphicsElementShape(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape) override;
        virtual bool IsCutterGraphicsElementShapeJoinable() const override;

        // 关联更新相关
        RegenDataId GetElementJoinTypeRdId() const override { return GetJoinTypeRdId(); }
        void MarkElementJoinTypeRdId() override { MarkJoinTypeRdId(); }

        virtual JoinType GetJoinType() override;
        bool SetJoinType(JoinType val);

        //切换平接与方接相关
        bool IsChangeJoinTypeAllowed() const override { return GetIsChangeJoinTypeAllowed__(); }
        bool SetIsChangeJoinTypeAllowed(bool isChangeJoinTypeAllowed) override { SetIsChangeJoinTypeAllowed__(isChangeJoinTypeAllowed); return true; }

        //切换主次关系相关
        bool IsChangePriAndSecAllowed() const override { return GetIsChangePriAndSecAllowed__(); }
        bool SetIsChangePriAndSecAllowed(bool isChangePriAndSecAllowed) override { SetIsChangePriAndSecAllowed__(isChangePriAndSecAllowed); return true; }

    private:
        bool ExecuteForAbutJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape);
        bool ExecuteForMiterJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape);
        bool ExecuteForSquareOffJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape);
        bool ExecuteForTTypeJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape);

        IElementJoin* GetElementJoin() const;
        std::pair<const IInstance*, bool>  GetFaceInstance(const IInstance* pRegenInstance, const IElementJoin* pInstanceJoin) const;
        JoinPosition GetJoinPosition(const IInstance* pInstance, ElementId joinId) const;

        //判断两个构件是否在端点可以连接，能连接返回连接点
        bool CanJoinAtEndPoint(const IInstance* pTargetInstance, const IInstance* pStandInstance, Vector3d& ptJoin);

        OwnerPtr<IGraphicsElementShape> GetJoinedGraphicsElementShape(const IInstance* pTargetInstance, const IGraphicsElementShape* pBaseGraphicsElementShape, const IInstance* pStandInstance, Vector3d& ptJoin, JoinType type, bool bIsExtendedFirst);
        void ReCalculateJoinAttachedAndAttachingRelation(IElementJoin* pElementJoin, JoinType type);
    public:
        // return partner's id and join end if join exists. return <InvalidId, WJT_INVALID> if no join exists.
        static std::pair<ElementId, JoinPosition> GetInstanceJoinPartnerByInstanceIdAndEnd(const IDocument* pDoc, ElementId elementId, JoinPosition joinEnd);

    public: //实现NdbObject接口
        virtual NdbObject* GetTopOwnerObject() const override
        {
            return nullptr;
        }
    };
}
